package chat.view.dialogs;

import chat.clients.XmppClient;
import chat.clients.fb.FBClient;
import chat.clients.gtalk.GTalkClient;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterGroup;
import swing.Dialog;
import swing.Images;

import javax.swing.*;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

import static java.awt.Color.black;
import static java.awt.event.MouseEvent.BUTTON1;
import static javax.swing.SwingConstants.CENTER;
import static javax.swing.SwingConstants.RIGHT;
import static javax.swing.tree.TreeSelectionModel.SINGLE_TREE_SELECTION;

public class ContactListDialog extends Dialog {
    /**
     *
     */
    private static final long serialVersionUID = -2331785427286152867L;

    public static final int CLIENT_ICON_SIZE = 24;

    private final RosterTree rosterTree = new RosterTree();

    public ContactListDialog() {
        super(swing.Dialog.Flag.CENTERED, Flag.PACKED);
        setTitle("Buddies");

        addClient(FBClient.INSTANCE);
        addClient(GTalkClient.INSTANCE);

        add(new JScrollPane(rosterTree));
        setSize(300, 500);
    }

    private final Map<XmppClient, java.util.List<RosterTree.EntryNode>> clientEntryNodes = new LinkedHashMap<>();

    public void addClient(final XmppClient client) {

        client.addObserver((o, arg) -> {
            if (arg == XmppClient.LOGGED_IN)
                rosterTree.clientLoggedIn(client);

            if (arg == XmppClient.LOGGED_OUT)
                rosterTree.clientLoggedOut(client);
        });
    }

    private class RosterTree extends JTree {

        /**
         *
         */
        private static final long serialVersionUID = 9096234398589440620L;
        private final DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
        private final Map<RosterGroup, GroupNode> groupNodes = new LinkedHashMap<>();
        private final DefaultTreeModel model = new DefaultTreeModel(root);

        private RosterTree() {
            setModel(model);
            getSelectionModel().setSelectionMode(SINGLE_TREE_SELECTION);

            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    Object component = getLastSelectedPathComponent();

                    if (component == null || !(component instanceof EntryNode))
                        return;

                    ((EntryNode) component).onClicked(e);
                }
            });

            setCellRenderer(new CellRenderer());

            setRootVisible(false);
        }

        public void clientLoggedIn(XmppClient client) {
            if (!clientEntryNodes.containsKey(client))
                clientEntryNodes.put(client, new ArrayList<>());

            java.util.List<EntryNode> list = clientEntryNodes.get(client);

            Collection<RosterEntry> entries = client.getRosterEntries();
            DefaultMutableTreeNode groupLess = null;

            System.out.println(entries.size());

            for (RosterEntry entry : entries) {
                EntryNode entryNode = new EntryNode(client, entry);

                Collection<RosterGroup> groups = entry.getGroups();
                if (groups.size() == 0) {
                    if (groupLess == null) {
                        groupLess = new DefaultMutableTreeNode("<Group less>");

                        root.add(groupLess);
                    }

                    groupLess.add(entryNode);
                } else
                    for (RosterGroup group : groups) {
                        if (!groupNodes.containsKey(group)) {
                            GroupNode groupNode = new GroupNode(group);
                            root.add(groupNode);
                            groupNodes.put(group, groupNode);
                        }

                        groupNodes.get(group).add(entryNode);
                    }

                list.add(entryNode);
            }

            expandPath(new TreePath(root.getPath()));

            revalidate();
            repaint();
        }

        public void clientLoggedOut(XmppClient client) {
            for (RosterTree.EntryNode node : clientEntryNodes.get(client))
                model.removeNodeFromParent(node);

            revalidate();
            repaint();
        }

        private class EntryNode extends RosterTreeNode {
            /**
             *
             */
            private static final long serialVersionUID = 814344596183731937L;
            private final XmppClient client;
            private final RosterEntry entry;

            public EntryNode(final XmppClient client, final RosterEntry entry) {
                super(entry.getName());
                this.client = client;
                this.entry = entry;
            }

            public void onClicked(MouseEvent e) {
                if (e.getClickCount() == 2 && e.getButton() == BUTTON1)
                    new ChatDialog(client, entry).setVisible(true);
            }

            public Component getRendererComponent() {
                JPanel panel = new JPanel();

                JLabel label = new JLabel(entry.getName());

                label.setIcon(getIcon(client));
                label.setHorizontalTextPosition(RIGHT);
                label.setVerticalTextPosition(CENTER);
                label.setBorder(new CompoundBorder(new LineBorder(black), new EmptyBorder(5, 15, 5, 15)));
                label.setMinimumSize(new Dimension(200, 0));

                panel.add(label);

                return panel;
            }

            private final Map<XmppClient, Icon> clientIcons = new LinkedHashMap<>();

            private Icon getIcon(XmppClient client) {
                if (!clientIcons.containsKey(client)) {
                    clientIcons.put(client, new ImageIcon(Images.loadImage(client.getClass(), "client_" + CLIENT_ICON_SIZE + "x" + CLIENT_ICON_SIZE + ".png")));
                }
                return clientIcons.get(client);
            }
        }

        private class GroupNode extends RosterTreeNode {
            /**
             *
             */
            private static final long serialVersionUID = 1522009736930385243L;

            public GroupNode(RosterGroup group) {
                super(group.getName());
            }
        }

        private abstract class RosterTreeNode extends DefaultMutableTreeNode {
            /**
             *
             */
            private static final long serialVersionUID = 1805177571811732017L;

            private RosterTreeNode(Object userObject) {
                super(userObject);
            }
        }

        private class CellRenderer extends DefaultTreeCellRenderer {
            private CellRenderer() {
                setRowHeight(0);
            }

            @Override
            public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
                if (value instanceof EntryNode)
                    return ((EntryNode) value).getRendererComponent();

                return super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
            }
        }
    }
}
